package com.star.spring.ratelimit.limiter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 本地滑动窗口限流器
 * 
 * @author star
 * @since 2025-01-24
 */
@Slf4j
@Component
public class LocalSlidingWindowLimiter {

    /**
     * 存储不同key的限流数据
     */
    private final ConcurrentHashMap<String, SlidingWindow> windows = new ConcurrentHashMap<>();

    /**
     * 滑动窗口数据结构
     */
    private static class SlidingWindow {
        private final long[] timestamps;
        private final AtomicLong index;
        private final int maxRequests;
        private final long windowSizeMs;

        public SlidingWindow(int maxRequests, long windowSizeMs) {
            this.maxRequests = maxRequests;
            this.windowSizeMs = windowSizeMs;
            this.timestamps = new long[maxRequests];
            this.index = new AtomicLong(0);
        }

        public boolean tryAcquire() {
            long currentTime = System.currentTimeMillis();
            long currentIndex = index.getAndIncrement() % maxRequests;
            
            // 清理过期的时间戳
            long cutoffTime = currentTime - windowSizeMs;
            int validCount = 0;
            
            for (int i = 0; i < maxRequests; i++) {
                if (timestamps[i] > cutoffTime) {
                    validCount++;
                }
            }
            
            if (validCount >= maxRequests) {
                return false;
            }
            
            timestamps[(int) currentIndex] = currentTime;
            return true;
        }
    }

    /**
     * 尝试获取请求许可
     * 
     * @param key 限流key
     * @param maxRequests 最大请求数
     * @param windowSizeSeconds 窗口大小（秒）
     * @return 是否获取成功
     */
    public boolean tryAcquire(String key, int maxRequests, int windowSizeSeconds) {
        SlidingWindow window = windows.computeIfAbsent(key, k -> 
                new SlidingWindow(maxRequests, windowSizeSeconds * 1000L));
        
        boolean acquired = window.tryAcquire();
        log.debug("Sliding window limiter - key: {}, maxRequests: {}, windowSize: {}s, acquired: {}", 
                key, maxRequests, windowSizeSeconds, acquired);
        return acquired;
    }

    /**
     * 尝试获取请求许可（使用默认参数）
     * 
     * @param key 限流key
     * @return 是否获取成功
     */
    public boolean tryAcquire(String key) {
        return tryAcquire(key, 100, 60);
    }

    /**
     * 移除限流器
     * 
     * @param key 限流key
     */
    public void removeLimiter(String key) {
        windows.remove(key);
        log.info("Removed sliding window limiter - key: {}", key);
    }

    /**
     * 清空所有限流器
     */
    public void clear() {
        windows.clear();
        log.info("Cleared all sliding window limiters");
    }
}
